#include <iostream>
#include <cmath>
#include <random>

const double SAMPLE_RATE = 1000.0;
const double CARRIER_FREQ = 50.0;
const double MOD_FREQ = 5.0;
const double MAX_AMPLITUDE = 1.0;
const double MOD_INDEX = 0.5;

int generate_cover_signal(double *cover, const int size)
{
    if (!cover || size <= 0)
        return -1;

    const double time_step = 1.0 / SAMPLE_RATE;
    for (int i = 0; i < size; ++i)
    {
        double t = i * time_step;
        cover[i] = MAX_AMPLITUDE * sin(2 * M_PI * CARRIER_FREQ * t);
    }
    return 0;
}

int simulate_digital_modulation_signal(unsigned char *message, const int size)
{
    if (!message || size <= 0)
        return -1;

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1);

    for (int i = 0; i < size; ++i)
    {
        message[i] = dis(gen);
    }
    return 0;
}

int simulate_analog_modulation_signal(double *message, const int size)
{
    if (!message || size <= 0)
        return -1;

    const double time_step = 1.0 / SAMPLE_RATE;
    for (int i = 0; i < size; ++i)
    {
        double t = i * time_step;
        message[i] = 0.5 * MAX_AMPLITUDE * sin(2 * M_PI * MOD_FREQ * t);
    }
    return 0;
}

int modulate_digital_frequency(double *cover, const int cover_len,
                               const unsigned char *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    const double freq_shift = CARRIER_FREQ * MOD_INDEX;
    const int samples_per_bit = cover_len / msg_len;

    for (int i = 0; i < cover_len; ++i)
    {
        int bit_idx = i / samples_per_bit;
        if (bit_idx >= msg_len)
            bit_idx = msg_len - 1;

        double freq = CARRIER_FREQ + (message[bit_idx] ? freq_shift : -freq_shift);
        double t = i / SAMPLE_RATE;
        cover[i] = MAX_AMPLITUDE * sin(2 * M_PI * freq * t);
    }
    return 0;
}

int modulate_digital_amplitude(double *cover, const int cover_len,
                               const unsigned char *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    const int samples_per_bit = cover_len / msg_len;

    for (int i = 0; i < cover_len; ++i)
    {
        int bit_idx = i / samples_per_bit;
        if (bit_idx >= msg_len)
            bit_idx = msg_len - 1;

        double amp = message[bit_idx] ? MAX_AMPLITUDE : MAX_AMPLITUDE / 2;
        double t = i / SAMPLE_RATE;
        cover[i] = amp * sin(2 * M_PI * CARRIER_FREQ * t);
    }
    return 0;
}

int modulate_digital_phase(double *cover, const int cover_len,
                           const unsigned char *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    const int samples_per_bit = cover_len / msg_len;

    for (int i = 0; i < cover_len; ++i)
    {
        int bit_idx = i / samples_per_bit;
        if (bit_idx >= msg_len)
            bit_idx = msg_len - 1;

        double phase = message[bit_idx] ? 0 : M_PI;
        double t = i / SAMPLE_RATE;
        cover[i] = MAX_AMPLITUDE * sin(2 * M_PI * CARRIER_FREQ * t + phase);
    }
    return 0;
}

int modulate_analog_frequency(double *cover, const int cover_len,
                              const double *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    const double max_freq_dev = CARRIER_FREQ * MOD_INDEX;
    double phase_integral = 0.0;

    for (int i = 0; i < cover_len; ++i)
    {
        int msg_idx = i * msg_len / cover_len;
        double freq = CARRIER_FREQ + max_freq_dev * message[msg_idx];
        phase_integral += 2 * M_PI * freq / SAMPLE_RATE;
        cover[i] = MAX_AMPLITUDE * sin(phase_integral);
    }
    return 0;
}

int modulate_analog_amplitude(double *cover, const int cover_len,
                              const double *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    for (int i = 0; i < cover_len; ++i)
    {
        int msg_idx = i * msg_len / cover_len;
        double amp = MAX_AMPLITUDE * (1 + MOD_INDEX * message[msg_idx]);
        double t = i / SAMPLE_RATE;
        cover[i] = amp * sin(2 * M_PI * CARRIER_FREQ * t);
    }
    return 0;
}

int modulate_analog_phase(double *cover, const int cover_len,
                          const double *message, const int msg_len)
{
    if (!cover || !message || cover_len <= 0 || msg_len <= 0)
        return -1;

    const double max_phase_dev = M_PI * MOD_INDEX;

    for (int i = 0; i < cover_len; ++i)
    {
        int msg_idx = i * msg_len / cover_len;
        double phase = max_phase_dev * message[msg_idx];
        double t = i / SAMPLE_RATE;
        cover[i] = MAX_AMPLITUDE * sin(2 * M_PI * CARRIER_FREQ * t + phase);
    }
    return 0;
}

int main()
{
    const int NUM_SAMPLES = 1000;
    const int MSG_LEN = 10;

    double carrier[NUM_SAMPLES];
    unsigned char digital_msg[MSG_LEN];
    double analog_msg[MSG_LEN];

    generate_cover_signal(carrier, NUM_SAMPLES);
    simulate_digital_modulation_signal(digital_msg, MSG_LEN);
    simulate_analog_modulation_signal(analog_msg, MSG_LEN);

    modulate_digital_frequency(carrier, NUM_SAMPLES, digital_msg, MSG_LEN);
    //modulate_digital_amplitude(carrier, NUM_SAMPLES, digital_msg, MSG_LEN);
    // modulate_digital_phase(carrier, NUM_SAMPLES, digital_msg, MSG_LEN);

    // modulate_analog_frequency(carrier, NUM_SAMPLES, analog_msg, MSG_LEN);
    // modulate_analog_amplitude(carrier, NUM_SAMPLES, analog_msg, MSG_LEN);
    // modulate_analog_phase(carrier, NUM_SAMPLES, analog_msg, MSG_LEN);

    std::cout << "Modulated Signal Samples:\n";
    for (int i = 0; i < 10; ++i)
    {
        std::cout << carrier[i] << "\n";
    }

    return 0;
}